package cn.com.websocket.service;

import cn.com.websocket.config.WebSocketConfig;
import cn.com.websocket.enums.MessageEnum;
import cn.com.websocket.handle.SocketHandle;
import cn.com.websocket.po.Message;
import cn.com.websocket.service.impl.AbsMessageStrategy;
import cn.com.websocket.util.EnumUtil;
import cn.com.websocket.util.SpringContextUtil;
import cn.com.websocket.util.StringUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@ServerEndpoint(value = "/webSocket/{username}",configurator = WebSocketConfig.class)
@Component
public class WebSocketServer {

    //建立连接成功调用
    @OnOpen
    public void onOpen(Session session, @PathParam(value = "username") String userName,EndpointConfig config){
        SocketHandle.sessionPools.put(userName, session);
        SocketHandle.addOnlineCount();
        String OFFLINE_PREFIX_KEY = "offline_";// 离线消息前缀
        String SELF_OFFLINE_PREFIX_KEY = String.format("%s%s:",OFFLINE_PREFIX_KEY,userName);//自己未读消息前缀
        System.out.println(userName + "加入webSocket！当前人数为" + SocketHandle.onlineNum);
        Stream<String> stream = SocketHandle.offlineMessage.keySet().stream().filter(string->string.startsWith(SELF_OFFLINE_PREFIX_KEY));
        long count = stream.count();
        if(count>0){
            // 接收离线消息
            List<String> keys = SocketHandle.offlineMessage.keySet().stream().filter(string->string.startsWith(SELF_OFFLINE_PREFIX_KEY)).collect(Collectors.toList());
            Integer sum = 0;
            Map<String,Object> _data = new HashMap<>();
            for(String key:keys){
                String otherUser = key.substring(SELF_OFFLINE_PREFIX_KEY.length());
                List<Message> offlineMsgList = SocketHandle.offlineMessage.get(key);
                int _offlineCount = null==offlineMsgList?0:offlineMsgList.size();
                sum+=_offlineCount;
                _data.put(otherUser,_offlineCount);
            }
            if(null!=keys&&keys.size()>0){
                System.out.println("您好，【"+userName+"】，您有["+count+"]个人的，["+sum+"]条未读消息!");
                System.out.println("有这些人给你发的消息："+ JSONObject.toJSONString(_data));
            }

            // 发送通知告诉当前用户 有 N 个用户 给自己 发送了 N 条未读 消息!!!!  TODO 除了建立连接时，推送未读消息之外？ 应该是实时推送!!!! 如何实现？
            try {
                session.getBasicRemote().sendText(JSONObject.toJSONString(_data));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @OnMessage
    public void onMessage(String message) throws IOException{
        Message msg = JSON.parseObject(message, Message.class);
        MessageEnum.MSG_STRATEGY strategy = getMsgStrategy(msg);
        AbsMessageStrategy absMessageStrategy = (AbsMessageStrategy) SpringContextUtil.getApplicationContext().getBean(strategy.getBeanName());
        absMessageStrategy.handleMessage(SocketHandle.sessionPools.get(msg.getSource()),msg);
    }

    private MessageEnum.MSG_STRATEGY getMsgStrategy(Message message){
        if(StringUtil.isEmpty(message.getStrategy())){ return MessageEnum.MSG_STRATEGY.ONLINE_OFFLINE; }
        MessageEnum.STRATEGY strategy = EnumUtil.getEnumByCode(MessageEnum.STRATEGY.class,message.getStrategy());
        if(null==strategy){ return MessageEnum.MSG_STRATEGY.ONLINE_OFFLINE; }
        return EnumUtil.getEnumByCode(MessageEnum.MSG_STRATEGY.class,strategy.getValue());
    }

    //关闭连接时调用
    @OnClose
    public void onClose(@PathParam(value = "username") String userName){
        SocketHandle.sessionPools.remove(userName);
        SocketHandle.subOnlineCount();
        System.out.println(userName + "断开webSocket连接！当前人数为" + SocketHandle.onlineNum);
    }

    @OnError
    public void onError(Session session, Throwable throwable){
        System.out.println("发生错误");
        throwable.printStackTrace();
    }
}
